//Random unit test for the Steward card
//Steward Effects:	+2 Cards or +2 coins or trash 2 cards
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"

typedef struct gameState G;

//C struct holds information about the options chosen when playing the card
typedef struct Option{
	int c1;
	int trash1;
	int trash2;
	int stewPos;

}Option;

void random_gamestate(G *game, Option *opt);
void pop(int *stack, int count);
int testPassed(G *g1, G *g2, Option *opt);
void print_results(int passed, int total);

int main(int argc, char *argv[]) {
	int i;
	int seed, num_tests;
	int test_passed;
	G before, after;
	Option opt;

	//get command line input
	if (argc != 3){
		printf("Usage: randomtestcard [seed] [number of tests]");
		return(0);
	}
	seed = atoi(argv[1]);
	num_tests = atoi(argv[2]);
	test_passed = 0;

	//seed the random generator
	SelectStream(1);
	PutSeed((long)seed);

	//test loop
	for (i = 0; i<num_tests; i++){
		//get a random gamestate
		random_gamestate(&before, &opt);

		//create a copy
		memcpy(&after, &before, sizeof(G));

		//play the card - c1 = option, c2 aand c3 = trash cards
		cardEffect(steward, opt.c1, opt.trash1, opt.trash2, &after, opt.stewPos, 0);

		//test results
		if (testPassed(&before, &after, &opt)){
			test_passed++;
		}
	}

	//print the results
	print_results(test_passed, num_tests);

	return 0;
}



//********************************************************
//Creates a random gamestate for testing
//Param: 	G *game - pointer to game struct to populate
//Param:	Option *opt - pointer to struct to hold random options
//Param: 	int seed - seed to generate random numbers
//Return: 	void
//********************************************************
void random_gamestate(G *game, Option *opt){
	int i;
	int r_player, r_handcount, r_deckcount, r_discardcount, option;
	int treasure1, treasure2;

	//set gamestate values to zero
	memset(game, 0, sizeof(G));

	//generate random inputs
	game->whoseTurn = r_player = (int)(Random() * (MAX_PLAYERS - 1));
	game->handCount[r_player] = r_handcount = (int)(Random() * (MAX_HAND - 5)) + 5; //at least 5 cards in hand
	game->discardCount[r_player] = r_discardcount = (int)(Random() * (MAX_DECK - r_handcount));
	game->deckCount[r_player] = r_deckcount = (int)(Random() * (MAX_DECK - (r_handcount + r_discardcount + 2))) + 2; //at least 2 cards in deck
	game->coins = (int)(Random() * 3);

	//populate game with dummy cards
	pop(game->hand[r_player], r_handcount);
	pop(game->discard[r_player], r_discardcount);
	pop(game->deck[r_player], r_discardcount);

	//add the steward card to the hand
	opt->stewPos = (int)(Random() * (r_handcount - 1));
	game->hand[r_player][opt->stewPos] = steward;

	//pick an option [1, 2, 3] with even distribution
	opt->c1 = (int)(Random() * 2) + 1;

	//if option 2, then set two deck cards to 75 so we can track them
	if (opt->c1 == 1){
		game->deck[r_player][r_deckcount - 1] = 75;
		game->deck[r_player][r_deckcount - 2] = 75;
	}

	//if option 3, then pick trash card positions and set values (50)
	if (opt->c1 == 3){

		//make sure trash card 1 isn't the steward
		do{
			opt->trash1 = (int)(Random() * (r_handcount - 1));
		} while (opt->trash1 == opt->stewPos);

		//make sure trash card 2 isn't the steward or trash card 1
		do{
			opt->trash2 = (int)(Random() * (r_handcount - 1));
		} while (opt->trash2 == opt->stewPos || opt->trash2 == opt->trash1);

		//place the cards in the hand
		game->hand[r_player][opt->trash1] = 50;
		game->hand[r_player][opt->trash2] = 50;
	}
}



//********************************************************
//Populates a stack of cards with dummy cards
//Param: 	int *stack - pointer to the stack of cards we'll populate
//Param:	int count - the size of the stack
//Return: 	void
//********************************************************
void pop(int *stack, int count){
	int i;
	for (i = 0; i<count; i++){
		stack[i] = 100;
	}
}



//********************************************************
//Compares two gamestates
//Param: 	G *g1 - pointer to the 'before' gamestate
//Param:	G *g2 - pointer to the 'after' gamestate
//Param:	Loc *loc - pointer to the location info struct
//Return: 	1 if tests passed, 0 if test failed
//********************************************************
int testPassed(G *g1, G *g2, Option *opt){
	int i, p, card, cardCount, c1, result;
	p = g2->whoseTurn;
	result = 1;
	c1 = opt->c1;

	//Choice 1: Draw 2 cards
	if (c1 == 1){
		//hand should have 1 more card (+2 draw -1 stew)
		if (g1->handCount[p] + 1 != g2->handCount[p]){
			printf("Error: %d cards in hand instead of %d!\n", g2->handCount[p], g1->handCount[p] + 1);
			result = 0;
		}

		//hand should have our two drawn cards (75s)
		cardCount = 0;
		for (i = 0; i<g2->handCount[p]; i++){
			card = g2->hand[p][i];
			if (card == 75) cardCount++;
		}
		if (cardCount != 2){
			printf("Error: %d draw cards in hand instead of 2!\n", cardCount);
			result = 0;
		}

		//deck should have 2 less cards
		if (g1->deckCount[p] - 2 != g2->deckCount[p]){
			printf("Error: %d cards in deck instead of %d!\n", g2->deckCount[p], g1->deckCount[p] - 2);
			result = 0;
		}

		//deck should have no 75s
		cardCount = 0;
		for (i = 0; i<g2->deckCount[p]; i++){
			card = g2->deck[p][i];
			if (card == 75) cardCount++;
		}
		if (cardCount != 0){
			printf("Error: %d draw cards in deck instead of 0!\n", cardCount);
			result = 0;
		}
	}

	//Choice 2: +2 coins
	if (c1 == 2){
		//hand should have 1 less card
		if (g1->handCount[p] - 1 != g2->handCount[p]){
			printf("Error: %d cards in hand instead of %d!\n", g2->handCount[p], g1->handCount[p] - 1);
			result = 0;
		}

		//should have 2 more coins
		if (g1->coins + 2 != g2->coins){
			printf("Error: player has %d coins instead of %d!\n", g2->coins, g1->coins + 2);
			result = 0;
		}
	}

	//Choice 3: trash 2 cards
	if (c1 == 3){
		//hand should have 3 less cards
		if (g1->handCount[p] - 3 != g2->handCount[p]){
			printf("Error: %d cards in hand instead of %d!\n", g2->handCount[p], g1->handCount[p] - 3);
			result = 0;
		}

		//hand shouldn't have any 50s in it
		cardCount = 0;
		for (i = 0; i<g2->handCount[p]; i++){
			card = g2->hand[p][i];
			if (card == 50){
				cardCount++;
			}
		}
		if (cardCount != 0){
			printf("Error: still have %d trash cards in hand!\n", cardCount);
			result = 0;
		}

		//discard shouldn't have any 50s in it
		cardCount = 0;
		for (i = 0; i<g2->discardCount[p]; i++){
			card = g2->discard[p][i];
			if (card == 50){
				cardCount++;
			}
		}
		if (cardCount != 0){
			printf("Error: %d trash cards ended up in discard pile!\n", cardCount);
			result = 0;
		}

		//played cards shouldn't have any 50s in it
		cardCount = 0;
		for (i = 0; i<g2->playedCardCount; i++){
			card = g2->playedCards[i];
			if (card == 50){
				cardCount++;
			}
		}
		if (cardCount != 0){
			printf("Error: %d trash cards ended up in played card pile!\n", cardCount);
			result = 0;
		}
	}

	//steward card shouldn't be in hand
	cardCount = 0;
	for (i = 0; i<g2->handCount[p]; i++){
		card = g2->hand[p][i];
		if (card == steward){
			cardCount++;
		}
	}
	if (cardCount != 0){
		printf("Error: steward card still in hand\n");
		result = 0;
	}

	//steward card should be in played cards pile
	cardCount = 0;
	for (i = 0; i<g2->playedCardCount; i++){
		card = g2->playedCards[i];
		if (card == steward){
			cardCount++;
		}
	}
	if (cardCount != 1){
		printf("Error: %d steward cards in played card pile instead of 1!\n", cardCount);
		result = 0;
	}

	//return the result of the tests
	return result;

}



//********************************************************
//Print the results of testing
//Param: 	int passed - number of tests that passed
//Param:	int total - total number of tests run
//Return: 	void
//********************************************************
void print_results(int passed, int total){
	double results = ((double)passed) / total;
	printf("---------------------\n");
	printf("%.f%% of test cases passed (%d/%d)\n", (results * 100), passed, total);
}
